﻿//
// Copyright 2024 Exhunter Technology Co.Ltd2.
//

using System.Threading;

namespace X18.Framework.Core.Lock
{
    /// <summary>
    /// 读写锁工具
    /// </summary>
    public static class ReaderWriterLockUtils
    {
        /// <summary>
        /// 获取读锁，并执行 active 方法
        /// </summary>
        public static T ReaderLock<T>(this ReaderWriterLock locker, int timeout, ReaderWriterLockActive<T> active)
        {
            // 获取读锁
            bool releaseLock = false;
            if (!locker.IsWriterLockHeld && !locker.IsReaderLockHeld)
            {
                locker.AcquireReaderLock(timeout);
                releaseLock = true;
            }
            // 执行 active 方法
            T result;
            try
            {
                result = active();
            }
            finally
            {
                if (releaseLock)
                {
                    locker.ReleaseReaderLock();
                }
            }
            return result;
        }

        /// <summary>
        /// 获取写锁，并执行 active 方法
        /// </summary>
        public static T WriterLock<T>(this ReaderWriterLock locker, int timeout, ReaderWriterLockActive<T> active)
        {
            // 获取写锁
            bool releaseLock = false;
            LockCookie cookie = default;
            if (!locker.IsWriterLockHeld)
            {
                releaseLock = true;
                if (locker.IsReaderLockHeld)
                {
                    cookie = locker.UpgradeToWriterLock(timeout);
                }
                else
                {
                    locker.AcquireWriterLock(timeout);
                }
            }
            // 执行 active 方法
            T result;
            try
            {
                result = active();
            }
            finally
            {
                if (releaseLock)
                {
                    if (cookie != default)
                    {
                        locker.DowngradeFromWriterLock(ref cookie);
                    }
                    else
                    {
                        locker.ReleaseWriterLock();
                    }
                }
            }
            return result;
        }
    }

    public delegate T ReaderWriterLockActive<T>();
}
